#include "RoFaceDetect2.h"

RoFaceDetect2::RoFaceDetect2(QObject *parent)
	: QObject(parent),
	nScale(16),
	nMaxFace(10),
	hEngineRect(nullptr),
	hEngineAge(nullptr),
	hEngineGender(nullptr),
	nRet(MERR_UNKNOWN),
	imgHeight(0),
	imgWidth(0),
	offInput{0},
	resultFaceNumber(0),
	pWorkMem(nullptr),
	pWorkMemAge(nullptr),
	pWorkMemGender(nullptr)
	
{
	init();
}

RoFaceDetect2::~RoFaceDetect2()
{
	
	//ASAE_FSDK_Uninit
	if (hEngineGender)
	{
		ASGE_FSDK_UninitGenderEngine(hEngineGender);
	}
	if (hEngineAge)
	{
		ASAE_FSDK_UninitAgeEngine(hEngineAge);
	}
	if (hEngineRect)
	{
		AFD_FSDK_UninitialFaceEngine(hEngineRect);
	}
	if (pWorkMem)
	{
		free(pWorkMem);
	}
	if (pWorkMemAge)
	{
		free(pWorkMemAge);
	}
	if (pWorkMemGender)
	{
		free(pWorkMemGender);
	}
}


void RoFaceDetect2::init()
{
	
	//ASAE_FSDK_Uninit
	if (hEngineGender)
	{
		ASGE_FSDK_UninitGenderEngine(hEngineGender);
	}
	if (hEngineAge)
	{
		ASAE_FSDK_UninitAgeEngine(hEngineAge);
	}
	if (hEngineRect)
	{
		AFD_FSDK_UninitialFaceEngine(hEngineRect);
	}

	if (pWorkMem)
	{
		free(pWorkMem);
	}
	pWorkMem = (MByte *)malloc(WORKBUF_SIZE);

	if (pWorkMem == nullptr)
	{
		isIniOK = false;
		emit signalError("memo init wrong");
		return;
	}
	if (pWorkMemAge)
	{
		free(pWorkMemAge);
	}
	pWorkMemAge = (MByte *)malloc(WORKBUF_SIZE);

	if (pWorkMemAge == nullptr)
	{
		isIniOK = false;
		emit signalError("age memo init wrong");
		return;
	}


	if (pWorkMemGender)
	{
		free(pWorkMemGender);
	}
	pWorkMemGender = (MByte *)malloc(WORKBUF_SIZE);

	if (pWorkMemGender == nullptr)
	{
		isIniOK = false;
		emit signalError("gender memo init wrong");
		return;
	}

	nRet = AFD_FSDK_InitialFaceEngine(APPID, SDKKey, pWorkMem, WORKBUF_SIZE, &hEngineRect, AFD_FSDK_OPF_0_HIGHER_EXT, nScale, nMaxFace);
	if (nRet != MOK)
	{
		isIniOK = false;
		emit signalError("sdk init wrong");
		return;
	}


	//get sdk version
	pVersionInfo = nullptr;
	pVersionInfo = AFD_FSDK_GetVersion(hEngineRect);


	///init age engine
	MRESULT rt = ASAE_FSDK_InitAgeEngine(APPID, SDKKey_AGE, pWorkMemAge, WORKBUF_SIZE, &hEngineAge);

	if (rt != MOK)
	{
		isIniOK = false;
		emit signalError("sdk age init wrong");
		return;
	}


	///init gender engine
	MRESULT rtg = ASGE_FSDK_InitGenderEngine(APPID, SDKKey_GENDER, pWorkMemGender, WORKBUF_SIZE, &hEngineGender);

	if (rtg != MOK)
	{
		isIniOK = false;
		emit signalError("sdk gender init wrong");
		return;
	}



	isIniOK = true;
}

QJsonDocument RoFaceDetect2::getFaceRect()
{
	return faceDeteDoc;
}

QJsonDocument RoFaceDetect2::getFaceAge()
{
	return faceAgeDoc;
}

QJsonDocument RoFaceDetect2::getFaceGender()
{
	return faceGenderDoc;
}

QJsonDocument RoFaceDetect2::getResult()
{
	QJsonDocument doc;
	QJsonArray arra,aRect,aAge,aGender;
	QJsonObject obj;
	/*aRect = faceDeteDoc.object().value("result").toArray();
	aAge = faceAgeDoc.object().value("result").toArray();
	aGender=faceGenderDoc.object().value("result").toArray();*/
	obj.insert("number", QJsonValue(resultFaceNumber));
	for (int i = 0; i < resultFaceNumber; i++)
	{
		QJsonObject face;
		face.insert("id", i);
		face.insert("top", QJsonValue(FaceRes->rcFace[i].top));
		face.insert("left", QJsonValue(FaceRes->rcFace[i].left));
		face.insert("right", QJsonValue(FaceRes->rcFace[i].right));
		face.insert("bottom", QJsonValue(FaceRes->rcFace[i].bottom));
		face.insert("orient", QJsonValue(FaceRes->lfaceOrient[i]));
		face.insert("age", QJsonValue(AgeRes.pAgeResultArray[i]));
		face.insert("gender", QJsonValue(GenderRes.pGenderResultArray[i]));
		arra.insert(i, QJsonValue(face));

	}
	obj.insert("result", QJsonValue(arra));
	faceResult.setObject(obj);
	return faceResult;
}

QRect RoFaceDetect2::getFaceRectById(int id)
{
	QRect rect;
	if(id>resultFaceNumber)
		return QRect();
	else
	{
		QJsonArray arra;
		arra = faceDeteDoc.object().value("result").toArray();
		auto obj = arra.at(id).toObject();
		rect.setTop(obj.value("top").toInt());
		rect.setBottom( obj.value("bottom").toInt());
		rect.setLeft(obj.value("left").toInt());
		rect.setRight(obj.value("right").toInt());
		return rect;

	}
}

int RoFaceDetect2::getFaceAgeById(int id)
{
	if (id>resultFaceNumber)
		return -1;
	else
	{
		QJsonArray arra;
		arra = faceAgeDoc.object().value("result").toArray();
		auto obj = arra.at(id).toObject();
		return obj.value("age").toInt();	

	}
}

int RoFaceDetect2::getFaceGenderById(int id)
{
	if (id>resultFaceNumber)
		return -1;
	else
	{
		QJsonArray arra;
		arra = faceAgeDoc.object().value("result").toArray();
		auto obj = arra.at(id).toObject();
		return obj.value("gender").toInt();

	}
}

QImage RoFaceDetect2::getFaceImageById(int id)
{
	if (id>resultFaceNumber)
		return QImage();
	else
	{
		auto rec=getFaceRectById(id);
		return image.copy(rec);

	}
	
}

bool RoFaceDetect2::initImage(QString image_file_name)
{
	image.load(image_file_name);
	if (image.isNull())
		return false;
	else
		return transletImage();
}

bool RoFaceDetect2::initImage(QImage &image_new)
{
	image = image_new;
	if (image.isNull())
		return false;
	else
		return transletImage();
}

void RoFaceDetect2::setScale(MInt32 new_scale)
{
	if ((new_scale < 2) || (new_scale > 50))
		return;
	nScale = new_scale;
}

void RoFaceDetect2::setMaxFaceNumber(MInt32 new_max_face_number)
{
	if ((new_max_face_number <= 0) ||(new_max_face_number>100))
		return;
	nMaxFace = new_max_face_number;
}

void RoFaceDetect2::detect()
{
	init();
	detectFaceRect();
	detectFaceAge();
	detectFaceGender();
	getResult();
	emit signalDetectFinished();

}

void RoFaceDetect2::detectFaceRect()
{
	FaceRes = nullptr;
	nRet = AFD_FSDK_StillImageFaceDetection(hEngineRect, &offInput, &FaceRes);
	if (nRet != MOK)
	{
		//cout << "face detection failed ,err code:" << nRet << endl;
		emit signalError("image detection wrong");
	}
	else
	{
		QJsonDocument doc;
		QJsonArray array;
		//cout << "OK,the number of face:" << FaceRes->nFace;
		for (int i = 0; i < FaceRes->nFace; i++)
		{
			QJsonObject obj;
			obj.insert("id", QJsonValue(i));
			obj.insert("top", QJsonValue(FaceRes->rcFace[i].top));
			obj.insert("left", QJsonValue(FaceRes->rcFace[i].left));
			obj.insert("right", QJsonValue(FaceRes->rcFace[i].right));
			obj.insert("bottom", QJsonValue(FaceRes->rcFace[i].bottom));
			obj.insert("orient", QJsonValue(FaceRes->lfaceOrient[i]));
			array.insert(i, QJsonValue(obj));
		}
		resultFaceNumber = FaceRes->nFace;
		QJsonObject obj2;
		obj2.insert("num", QJsonValue(FaceRes->nFace));
		obj2.insert("result", QJsonValue(array));
		doc.setObject(obj2);
		faceDeteDoc = doc;
		qDebug() << doc;
		
		//getAge();
		//return doc;
	}

}

void RoFaceDetect2::detectFaceAge()
{
	AgeFaceInput.pFaceRectArray = FaceRes->rcFace;
	AgeFaceInput.pFaceOrientArray = FaceRes->lfaceOrient;
	AgeFaceInput.lFaceNumber = FaceRes->nFace;
	QJsonDocument doc;
	QJsonArray arra;
	QJsonObject obj;

	AgeRes = { 0 };
	auto mrt = ASAE_FSDK_AgeEstimation_StaticImage(hEngineAge, &offInput, &AgeFaceInput, &AgeRes);
	//if(mrt!=MOK)
	if (AgeRes.lFaceNumber > 0)
	{
		int faceNum = AgeRes.lFaceNumber;
		for (int i = 0; i < faceNum; i++)
		{
			QJsonObject obj2;
			int temp = AgeRes.pAgeResultArray[i];
			obj2.insert("index", QJsonValue(i));
			obj2.insert("age", QJsonValue(AgeRes.pAgeResultArray[i]));
			arra.insert(i, QJsonValue(obj2));
			//AgeRes.pAgeResultArray++;
		}
		obj.insert("num", QJsonValue(faceNum));
		obj.insert("result", QJsonValue(arra));
		doc.setObject(obj);
		faceAgeDoc = doc;

	}
	else
	{
		faceAgeDoc = QJsonDocument();
	}
}
void RoFaceDetect2::detectFaceGender()
{
	GenderFaceInput.pFaceRectArray = FaceRes->rcFace;
	GenderFaceInput.pFaceOrientArray = FaceRes->lfaceOrient;
	GenderFaceInput.lFaceNumber = FaceRes->nFace;
	QJsonDocument doc;
	QJsonArray arra;
	QJsonObject obj;

	GenderRes = { 0 };
	auto mrt = ASGE_FSDK_GenderEstimation_StaticImage(hEngineGender, &offInput, &GenderFaceInput, &GenderRes);
	//if(mrt!=MOK)
	if (GenderRes.lFaceNumber > 0)
	{
		int faceNum = GenderRes.lFaceNumber;
		for (int i = 0; i < faceNum; i++)
		{
			QJsonObject obj2;
			int temp = GenderRes.pGenderResultArray[i];
			obj2.insert("index", QJsonValue(i));
			obj2.insert("gender", QJsonValue(GenderRes.pGenderResultArray[i]));
			arra.insert(i, QJsonValue(obj2));
			//AgeRes.pAgeResultArray++;
		}
		obj.insert("num", QJsonValue(faceNum));
		obj.insert("result", QJsonValue(arra));
		doc.setObject(obj);
		faceGenderDoc = doc;

	}
	else
	{
		faceGenderDoc = QJsonDocument();
	}
}

bool RoFaceDetect2::transletImage()
{
	auto tempimage = image.convertToFormat(QImage::Format_RGB888);
	image = tempimage;
	if (image.isNull())
	{
		return false;
	}
	imgWidth = image.width();
	imgHeight = image.height();
	int biBitCount = image.bitPlaneCount();
	if (24 == biBitCount)
	{
		int lineByte = ((imgWidth) * biBitCount / 8 + 3) / 4 * 4;
		//readBmpQByteArra24(img_input, (uint8_t**)&offInput.ppu8Plane[0], &offInput.i32Width, &offInput.i32Height);
		//readBmpQByteArra24(QImage img_org, uint8_t **imageData, int *pWidth, int *pHeight)
		//*imageData offInput
		offInput.ppu8Plane[0]	= (uint8_t *)malloc(lineByte * (imgHeight));
		uint8_t * data = (uint8_t *)malloc(lineByte * imgHeight);
		QBuffer *buf = new QBuffer;
		image.save(buf, "BMP");
		auto byte = buf->data();
		auto da = byte.right(byte.size() - 54);
		memcpy(data, da.data(), da.size());
		for (int i = 0; i <imgHeight; i++)
		{
			for (int j = 0; j < imgWidth; j++)
			{
				memcpy((offInput.ppu8Plane[0]) + i * (imgWidth) * 3 + j * 3, data + (((imgHeight) - 1) - i) * lineByte + j * 3, 3);
			}
		}
		free(data);
		offInput.u32PixelArrayFormat = (ASVL_PAF_RGB24_B8G8R8);
		
		offInput.i32Height = imgHeight;
		offInput.i32Width = imgWidth;
		offInput.pi32Pitch[0] = offInput.i32Width * 3;
		return true;
	}
	else
	{
		emit signalError("image translet is not 24bit");
		return false;
	}
}
